<?php
/**
 * Copyright 2011  SURFfoundation
 * 
 * This file is part of ESCAPE.
 * 
 * ESCAPE is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * ESCAPE is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with ESCAPE.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * For more information:
 * http://escapesurf.wordpress.com/
 * http://www.surffoundation.nl/
 * 
 * Contact: d.vierkant@utwente.nl
 * 
 * @license http://www.gnu.org/licenses/gpl.html GNU GPLv3
 */
?>
<?php
/**
 * Extract metadata
 * 
 * Extract metadata from a URL.
 */
class escape_repositoryui_rpc_ExtractMetadata extends escape_repositoryui_RpcHandler
{
	public function handleRequest()
	{
		$aggregationUri = $_REQUEST['aggregationUri'];
		$resourceUrl = trim($_REQUEST['resourceUrl']);
		$typeUri = $_REQUEST['typeUri'];
		
		// fetch the aggregation
		$aggregation = $this->repository->getOreAggregationByUri($aggregationUri);
		if($aggregation === null)
		{
			throw new escape_repositoryui_exception_Exception('Failed to fetch the specified aggregation');
		}
		
		// use authorization to limit usage of the extraction facilities to actual ESCAPE users
		$user = $this->repositoryUi->user;
		if($user === null || !($user->hasSystemRole(escape_repository_User::$role_administrator) || $aggregation->hasEditor($user->getUri()) || $aggregation->hasOwner($user->getUri())))
		{
			throw new escape_repositoryui_exception_Rpc("Not authorized");
		}

		$threshold = $this->repository->config['entityresolution']['threshold'];
		
		// setup the meta mapper
		$metaMapper = new escape_metamapper_MetaMapper($this->repository->config['metamapper'], $this->repository->repositorySchema);
		
		// setup the aggregation matcher
		$matcher = new escape_entityresolution_AggregationMatcher($this->repository, $aggregation);
		
		// setup the meta extractor
		$metaExtractor = new metaextractor_MetaExtractor($this->repository->config['metaextractor']);
	
		// extract the metadata
		$resultsByExtactorId = $metaExtractor->fetchUrlMetadata($resourceUrl);
		
//		print_r($resultsByExtactorId); die;
		
		// process the extracted metadata
		$matchedMetadata = array();
		foreach($resultsByExtactorId as $results)
		{
			foreach($results as $result)
			{
				/* @var $result metaextractor_Result */
				
				// create a result item
				$matchedMetadataResult = array();
				$matchedMetadataResult['id'] = $result->getExtractorId();
				$matchedMetadataResult['name'] = $result->getExtractorName();
				
				$rdfDocument = $result->getRdfDocument();

				// map the extracted metadata
				$mappedResult = $metaMapper->mapMetadata($rdfDocument, $result->getSubjectUri(), $typeUri);
				
				$mappedRdfDocument = $mappedResult->getRdfDocument();
				$mappedRdfResource = $mappedRdfDocument->getResourceBySubject($mappedResult->getSubjectUri());
				
//				print $result->getExtractorId() . "\n";
//				print_r($mappedRdfResource);
				
				$predicates = $mappedRdfResource->getPredicates();
				
				$matchedExtractorMetadata = array();
				
				if($result->getSubjectUri() !== $resourceUrl)
				{
					$extractorResult = array();
					$extractorResult['label'] = $this->repository->repositorySchema->getResourceLabel('http://purl.utwente.nl/ns/escape-system.owl#externalUri');
					$extractorResult['predicate'] = 'http://purl.utwente.nl/ns/escape-system.owl#externalUri';
					$extractorResult['object'] = $result->getSubjectUri();
					$matchedExtractorMetadata[] = $extractorResult;
				}
				
				foreach($predicates as $predicate)
				{
					// filter non assignable properties
					if(!$this->repository->repositorySchema->isNonAssignableProperty($predicate))
					{
						$objects = $mappedRdfResource->getObjects($predicate);
	
						foreach($objects as $object)
						{
							// check if this is a relation
							$isRelation = false;
							$hasTitle = false;
							
							// see if we can find the related object
							$relatedRdfResource = $mappedRdfDocument->getResourceBySubject($object);
							
							if($relatedRdfResource)
							{
								$isRelation = true;
								
								// try to find a title for the related object
								$relatedRdfResourceRdfTypes = $relatedRdfResource->getRdfTypes();
								
								$classTitlePropertyUris = $this->repository->repositorySchema->getClassTitlePropertyUriList($relatedRdfResourceRdfTypes);
								
								foreach($classTitlePropertyUris as $classTitlePropertyUri)
								{
									$titles = $relatedRdfResource->getObjects($classTitlePropertyUri);
									if($titles)
									{
										// if titles are found, replace the object of this property with the titles
										$hasTitle = true;
										$object = implode("\n", $titles);
										break;
									}
								}
							}
							
							if(!$isRelation || ($isRelation && $hasTitle))
							{
								// add a property to the result
								$extractorResult = array();
								$extractorResult['label'] = $this->repository->repositorySchema->getResourceLabel($predicate);
								$extractorResult['predicate'] = $predicate;
								$extractorResult['object'] = $object;
								
								// for relations...
								if($isRelation)
								{
									// add class selector trees
									$extractorResult['classSelectorTrees'] = $this->repositoryUi->getClassSelectorTrees($relatedRdfResource->getRdfTypes());
									
									// add the related object RDF
									$extractorResult['relatedObjectRdfXml'] = $relatedRdfResource->getRdfXml(true);

									// find matching objects
									$matchedRelatedObjects = array();
									
									$relatedRdfDocument = simplerdf_RdfDocument::createRdfDocument();
									$relatedRdfDocument->addResource($relatedRdfResource);

									$matcherResult = $matcher->findMatches($relatedRdfDocument, $relatedRdfResource->getSubject(), $threshold);
									
									// add at most 5 of these matched objects to the result
									$matcherResultEntries = $matcherResult->getEntries(5);
									foreach($matcherResultEntries as $matcherResultEntry)
									{
										/* @var $matcherResultEntry entityresolution_ResultEntry */
										
										$aggregatedResource = $this->repository->getOreAggregatedResourceByUri($matcherResultEntry->getSubjectUri());
										
										$rdfTypes = $aggregatedResource->getRdfTypes();
										$typeLabel = $this->repository->repositorySchema->getResourceLabel($rdfTypes[0]);
										
										$matchedRelatedObject = array();
										$matchedRelatedObject['score'] = $matcherResultEntry->getScore();
										$matchedRelatedObject['uri'] = $aggregatedResource->getUri();
										$matchedRelatedObject['title'] = $aggregatedResource->getTitle();
										$matchedRelatedObject['typeLabel'] = $typeLabel;
										$matchedRelatedObjects[] = $matchedRelatedObject;
									}
									
									$extractorResult['matchedRelatedObjects'] = $matchedRelatedObjects;
								}
								
								$matchedExtractorMetadata[] = $extractorResult;
							}
						}
					}
				}
				$matchedMetadataResult['metadata'] = $matchedExtractorMetadata;
				
				$matchedMetadata[] = $matchedMetadataResult;
			}
		}
//		print_r($matchedMetadata);
		
		// send the result out in JSON format
		print json_encode($matchedMetadata);
	}
}
